package com.centaline.utils;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.CharEncoding;
import org.apache.commons.lang3.text.WordUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by caoyuan7 on 2017/9/4.
 */
public class StringUtils {

    private static Logger logger =  LoggerFactory.getLogger(StringUtils.class);
    public static final String EMPTY = "";

    public static final String[] EMPTY_STRING_ARRAY = new String[0];

    private static final Pattern CRLF = Pattern.compile("(\r\n|\r|\n|\n\r)");

    private static final Pattern KVP_PATTERN = Pattern.compile("([_.a-zA-Z0-9][-_.a-zA-Z0-9]*)[=](.*)"); // key value pair
    // pattern.
    private static final Pattern INT_PATTERN = Pattern.compile("^\\d+$");

    public static boolean isBlank(String str) {
        if (str == null || str.length() == 0)
            return true;
        return false;
    }

    /**
     * is empty string.
     *
     * @param str
     *            source string.
     * @return is empty.
     */
    public static boolean isEmpty(String str) {
        if (str == null || str.length() == 0)
            return true;
        return false;
    }

    /**
     * is not empty string.
     *
     * @param str
     *            source string.
     * @return is not empty.
     */
    public static boolean isNotEmpty(String str) {
        return str != null && str.length() > 0;
    }

    /**
     *
     * @param s1
     * @param s2
     * @return equals
     */
    public static boolean isEquals(String s1, String s2) {
        if (s1 == null && s2 == null)
            return true;
        if (s1 == null || s2 == null)
            return false;
        return s1.equals(s2);
    }

    /**
     * is integer string.
     *
     * @param str
     * @return is integer
     */
    public static boolean isInteger(String str) {
        if (str == null || str.length() == 0)
            return false;
        return INT_PATTERN.matcher(str).matches();
    }

    public static int parseInteger(String str) {
        if (!isInteger(str))
            return 0;
        return Integer.parseInt(str);
    }

    /**
     * Returns true if s is a legal Java identifier.
     * <p>
     * <a href="http://www.exampledepot.com/egs/java.lang/IsJavaId.html">more
     * info.</a>
     */
    public static boolean isJavaIdentifier(String s) {
        if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) {
            return false;
        }
        for (int i = 1; i < s.length(); i++) {
            if (!Character.isJavaIdentifierPart(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     *
     * @param values
     * @param value
     * @return contains
     */
    public static boolean isContains(String[] values, String value) {
        if (value != null && value.length() > 0 && values != null
                && values.length > 0) {
            for (String v : values) {
                if (value.equals(v)) {
                    return true;
                }
            }
        }
        return false;
    }

    public static boolean isNumeric(String str) {
        if (str == null) {
            return false;
        }
        int sz = str.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isDigit(str.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * translat.
     *
     * @param src
     *            source string.
     * @param from
     *            src char table.
     * @param to
     *            target char table.
     * @return String.
     */
    public static String translat(String src, String from, String to) {
        if (isEmpty(src))
            return src;
        StringBuilder sb = null;
        int ix;
        char c;
        for (int i = 0, len = src.length(); i < len; i++) {
            c = src.charAt(i);
            ix = from.indexOf(c);
            if (ix == -1) {
                if (sb != null)
                    sb.append(c);
            } else {
                if (sb == null) {
                    sb = new StringBuilder(len);
                    sb.append(src, 0, i);
                }
                if (ix < to.length())
                    sb.append(to.charAt(ix));
            }
        }
        return sb == null ? src : sb.toString();
    }

    /**
     * split.
     *
     * @param ch
     *            char.
     * @return string array.
     */
    public static String[] split(String str, String ch) {
        if (isEmpty(str)) {
            return EMPTY_STRING_ARRAY;
        }
        String[] arrays = str.split(ch);
        return ArrayUtils.isEmpty(arrays)? EMPTY_STRING_ARRAY : arrays;
    }

    public static List<String> splitList(String str, String ch) {
        if (isEmpty(str)) {
            return new ArrayList<String>(0);
        }
        String[] arrays = split(str, ch);
        if (ArrayUtils.isEmpty(arrays)) {
            return new ArrayList<String>();
        }
        List<String> list = CollectionUtils.arrayToList(arrays);
        return list == null ? new ArrayList<String>() : list;
    }

    /**
     * join string.
     *
     * @param array
     *            String array.
     * @return String.
     */
    public static String join(String[] array) {
        if (array.length == 0)
            return "";
        StringBuilder sb = new StringBuilder();
        for (String s : array)
            sb.append(s);
        return sb.toString();
    }

    /**
     * join string like javascript.
     *
     * @param array
     *            String array.
     * @param split
     *            split
     * @return String.
     */
    public static String join(String[] array, char split) {
        if (array.length == 0)
            return "";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            if (i > 0)
                sb.append(split);
            sb.append(array[i]);
        }
        return sb.toString();
    }

    /**
     * join string like javascript.
     *
     * @param array
     *            String array.
     * @param split
     *            split
     * @return String.
     */
    public static String join(String[] array, String split) {
        if (array.length == 0)
            return "";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            if (i > 0)
                sb.append(split);
            sb.append(array[i]);
        }
        return sb.toString();
    }

    public static String join(Collection<String> coll, String split) {
        if (coll.isEmpty())
            return "";

        StringBuilder sb = new StringBuilder();
        boolean isFirst = true;
        for (String s : coll) {
            if (isFirst)
                isFirst = false;
            else
                sb.append(split);
            sb.append(s);
        }
        return sb.toString();
    }

    /**
     * parse key-value pair.
     *
     * @param str
     *            string.
     * @param itemSeparator
     *            item separator.
     * @return key-value map;
     */
    private static Map<String, String> parseKeyValuePair(String str,
                                                         String itemSeparator) {
        String[] tmp = str.split(itemSeparator);
        Map<String, String> map = new HashMap<String, String>(tmp.length);
        for (int i = 0; i < tmp.length; i++) {
            Matcher matcher = KVP_PATTERN.matcher(tmp[i]);
            if (matcher.matches() == false)
                continue;
            map.put(matcher.group(1), matcher.group(2));
        }
        return map;
    }

    public static String getQueryStringValue(String qs, String key) {
        Map<String, String> map = StringUtils.parseQueryString(qs);
        return map.get(key);
    }

    /**
     * parse query string to Parameters.
     *
     * @param qs
     *            query string.
     * @return Parameters instance.
     */
    public static Map<String, String> parseQueryString(String qs) {
        if (qs == null || qs.length() == 0)
            return new HashMap<String, String>();
        return parseKeyValuePair(qs, "\\&");
    }

    public static String toQueryString(Map<String, String> ps) {
        StringBuilder buf = new StringBuilder();
        if (ps != null && ps.size() > 0) {
            for (Map.Entry<String, String> entry : new TreeMap<String, String>(
                    ps).entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key != null && key.length() > 0 && value != null
                        && value.length() > 0) {
                    if (buf.length() > 0) {
                        buf.append("&");
                    }
                    buf.append(key);
                    buf.append("=");
                    buf.append(value);
                }
            }
        }
        return buf.toString();
    }

    public static String toQueryStringEncode(Map<String, String> ps) {
        StringBuilder buf = new StringBuilder();
        if (ps != null && ps.size() > 0) {
            for (Map.Entry<String, String> entry : new TreeMap<String, String>(ps).entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key != null && key.length() > 0 && value != null
                        && value.length() > 0) {
                    if (buf.length() > 0) {
                        buf.append("&");
                    }
                    buf.append(key);
                    buf.append("=");
                    buf.append(encode(value));
                }
            }
        }
        return buf.toString();
    }

    public static String camelToSplitName(String camelName, String split) {
        if (camelName == null || camelName.length() == 0) {
            return camelName;
        }
        StringBuilder buf = null;
        for (int i = 0; i < camelName.length(); i++) {
            char ch = camelName.charAt(i);
            if (ch >= 'A' && ch <= 'Z') {
                if (buf == null) {
                    buf = new StringBuilder();
                    if (i > 0) {
                        buf.append(camelName.substring(0, i));
                    }
                }
                if (i > 0) {
                    buf.append(split);
                }
                buf.append(Character.toLowerCase(ch));
            } else if (buf != null) {
                buf.append(ch);
            }
        }
        return buf == null ? camelName : buf.toString();
    }

    public static boolean equals(String str1, String str2) {
        if (str1 == null) {
            return str2 == null;
        }

        return str1.equals(str2);
    }

    public static boolean equalsIgnoreCase(String str1, String str2) {
        if (str1 == null) {
            return str2 == null;
        }

        return str1.equalsIgnoreCase(str2);
    }

    private StringUtils() {
    }

    private static String getZeroLen(int len) {
        String str = "";
        for (int i = 0; i < len; i++) {
            str = str + "0";
        }
        return str;
    }

    public static String comdify(String value) {
        DecimalFormat df = null;
        if (value.indexOf(".") > 0) {
            int i = value.length() - value.indexOf(".") - 1;
            switch (i) {
                case 0:
                    df = new DecimalFormat("###,##0");
                    break;
                case 1:
                    df = new DecimalFormat("###,##0.0");
                    break;
                case 2:
                    df = new DecimalFormat("###,##0.00");
                    break;
                case 3:
                    df = new DecimalFormat("###,##0.000");
                    break;
                case 4:
                    df = new DecimalFormat("###,##0.0000");
                    break;
                default:
                    df = new DecimalFormat("###,##0.00000");
                    break;
            }
        } else {
            df = new DecimalFormat("###,##0");
        }
        double number = 0.0D;
        try {
            number = Double.parseDouble(value);
        } catch (Exception e) {
            number = 0.0D;
        }
        return df.format(number);
    }

    public static String getNumber(Object value, Object isShowComdify,
                                   Object decimalValue, Object coinValue) {
        if (value == null)
            return "";
        String val = value.toString();
        if (isShowComdify != null) {
            boolean result = Boolean.valueOf(isShowComdify.toString())
                    .booleanValue();
            Double douvalue = Double.valueOf(Double.parseDouble(val));
            DecimalFormat df = new DecimalFormat("");
            val = df.format(douvalue);
            if (!result) {
                val = val.replace(",", "");
            }
        }
        if (decimalValue != null) {
            int len = Integer.parseInt(decimalValue.toString());
            if (len > 0) {
                int idx = val.indexOf(".");
                if (idx == -1) {
                    val = val + "." + getZeroLen(len);
                } else {
                    String intStr = val.substring(0, val.indexOf("."));
                    String decimal = val.substring(val.indexOf(".") + 1);
                    if (decimal.length() > len) {
                        Double douvalue = Double.valueOf(Double.parseDouble(val
                                .replace(",", "")));
                        DecimalFormat df = new DecimalFormat("");
                        df.setMaximumFractionDigits(len);
                        String tmp = df.format(douvalue);
                        if (tmp.indexOf(".") == -1) {
                            val = intStr + "." + getZeroLen(len);
                        } else {
                            decimal = tmp.substring(tmp.indexOf(".") + 1);
                            val = intStr + "." + decimal;
                        }
                    } else if (decimal.length() < len) {
                        int tmp = len - decimal.length();
                        val = val + getZeroLen(tmp);
                    }
                }
            }
        }
        if (coinValue != null) {
            val = coinValue.toString() + val;
        }
        return val;
    }

    public static String trimSufffix(String toTrim, String trimStr) {
        while (toTrim.endsWith(trimStr)) {
            toTrim = toTrim.substring(0, toTrim.length() - trimStr.length());
        }
        return toTrim;
    }

    public static String trimPrefix(String toTrim, String trimStr) {
        while (toTrim.startsWith(trimStr)) {
            toTrim = toTrim.substring(trimStr.length());
        }
        return toTrim;
    }

    public static String trim(String toTrim, String trimStr) {
        return trimSufffix(trimPrefix(toTrim, trimStr), trimStr);
    }

    public static String trim(String str) {
        if (isNotEmpty(str)) {
            return str.trim();
        }
        return str;
    }

    public static String replaceAll(String toReplace, String replace,
                                    String replaceBy) {
        replaceBy = replaceBy.replaceAll("\\$", "\\\\\\$");
        return toReplace.replaceAll(replace, replaceBy);
    }

    public static String substringBefore(String sourceStr, String beforeStr) {
        String[] strs = split(sourceStr, beforeStr);
        if (strs != null && strs.length > 0) {
            return strs[0];
        }
        return null;
    }

    public static String capitalize(String str) {
        return WordUtils.capitalize(str);
    }

    public static String uncapitalize(String str) {
        return WordUtils.uncapitalize(str);
    }

    @SuppressWarnings("deprecation")
    public static String encode(String str) {
        try {
            return  URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String subString(String str, int len) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        if (str.length() > len) {
            return str.substring(0, len);
        }
        return str;
    }

    public static String delCrlf(String str) {
        Matcher m = CRLF.matcher(str);
        if (m.find()) {
            str = m.replaceAll("");
        }
        return str;
    }

    public static String newStringUtf8(byte[] bytes) {
        return StringUtils.newString(bytes, CharEncoding.UTF_8);
    }

    public static String newString(byte[] bytes, String charsetName) {
        if (bytes == null) {
            return null;
        }
        try {
            return new String(bytes, charsetName);
        } catch (UnsupportedEncodingException e) {
            throw StringUtils.newIllegalStateException(charsetName, e);
        }
    }

    private static IllegalStateException newIllegalStateException(String charsetName, UnsupportedEncodingException e) {
        return new IllegalStateException(charsetName + ": " + e);
    }

    public static byte[] getBytesUtf8(String string) {
        return StringUtils.getBytesUnchecked(string, CharEncoding.UTF_8);
    }

    public static byte[] getBytesUnchecked(String string, String charsetName) {
        if (string == null) {
            return null;
        }
        try {
            return string.getBytes(charsetName);
        } catch (UnsupportedEncodingException e) {
            throw StringUtils.newIllegalStateException(charsetName, e);
        }
    }
}
